package com.github.cdisk.xtrans.ui.toolbox;

import java.lang.reflect.Field;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TreeEditor;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.VerifyEvent;
import org.eclipse.swt.events.VerifyListener;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;

import com.github.cdisk.xtrans.annotiation.Attribute;
import com.github.cdisk.xtrans.connect.Connect;
import com.github.cdisk.xtrans.core.BaseComponent;
import com.github.cdisk.xtrans.ui.Context;
import com.github.cdisk.xtrans.ui.Operation;
import com.github.cdisk.xtrans.ui.util.ComponentReflect;
import com.github.cdisk.xtrans.ui.widget.MoreButtonText;
import com.github.cdisk.xtrans.ui.widget.SqlTextDialog;
import com.github.cdisk.xtrans.ui.widget.TextDialog;

/**
 * 右侧属性栏加载类
 * 通过读取元件的属性，在右侧属性栏中加载出属性编辑框
 * @author Cdisk
 *
 */
public class AttributeBoxLoader {

	private Tree attributeTree;
	private TreeEditor attributeEditor;

	/** 当前正在编辑的元件 */
	private BaseComponent component;
	
	/** 当前编辑元件的类型 */
	private String currentType;

	/** 当前编辑元件的ID */
	private String currentId;

	/**
	 * 初始化
	 * @param context 主面板控件组
	 */
	public AttributeBoxLoader(Context context) {
		this.attributeTree = context.getAttribute();
		this.attributeEditor = new TreeEditor(attributeTree);
		
		/* 当编辑组件失去焦点时，清理编辑状态。 */
		FocusListener focusListener = new FocusListener() {
			@Override
			public void focusLost(FocusEvent e) {
				clearEditor();
			}
			@Override
			public void focusGained(FocusEvent e) {}
		};
		
		/* 右侧属性树中的内容点击事件 */
		attributeTree.addMouseListener(new MouseAdapter() {

			@Override
			public void mouseDown(MouseEvent e) {
				Point p = new Point(e.x, e.y);

				// 通过点击位置的y坐标和第一列的任意x坐标获取当前行项目，其他列对应的item为null
				final TreeItem item = getCurrentItem(attributeTree, e.y);
				if (item == null)
					return;
				
				/* 销毁上一次的编辑控件。 */
				Control old = attributeEditor.getEditor();
				if (old != null) {
					old.dispose();
				}

				final int currentCol = getColId(attributeTree, item, p);
				if (currentCol != 1)
					return; // 只能编辑第二列，第一列是属性名称，第三列是属性说明，都不能编辑。
				
				String name = item.getText(0); // 获取属性名称

				if ("type".equals(item.getText(0))) // 属性中的“元件类型”字段，不可编辑
					return;

				String type = (String) item.getData("type"); // 获取数据类型
				if (type == null)
					return; // 属性类型为空，可能是根节点，跳过

				switch (type) {
					case "boolean":
					case "java.lang.Boolean": {
						Button check = new Button(attributeTree, SWT.CHECK);
						check.addFocusListener(focusListener);
						check.setSelection("true".equals(item.getText(currentCol)));
						check.setText(String.valueOf(check.getSelection()));
						check.addSelectionListener(new SelectionAdapter() {
							public void widgetSelected(SelectionEvent e) {
								/* 将修改值设置回对象 */
								componentSetValue(name, check.getSelection()); // 更新对象值
								check.setText(String.valueOf(check.getSelection())); // 更新属性面板
								item.setText(currentCol, String.valueOf(check.getSelection())); // 更新属性面板
								context.getCanvas().redraw(); // 修改了名称，应该重绘
							}
						});
						attributeEditor.minimumWidth = item.getBounds(currentCol).width;
						attributeEditor.setEditor(check, item, currentCol);
						break;
					}
					case "com.github.cdisk.xtrans.connect.Connect": {
						Combo combo = new Combo(attributeTree, SWT.NONE);
						combo.addFocusListener(focusListener);
						combo.setForeground(item.getForeground());
						for (Connect conn : Operation.CONFIG.connects) {
							combo.add(conn.getId());
						}
						combo.setText(item.getText(currentCol));
						combo.setFocus();
						combo.addModifyListener(new ModifyListener() {
							public void modifyText(ModifyEvent e) {
								/* 将修改值设置回对象 */
								componentSetValue(name, Operation.CONFIG.findConnectById(combo.getText())); // 更新对象属性
								item.setText(currentCol, combo.getText()); // 更新属性面板
								context.getCanvas().redraw(); // 修改了，应该重绘
							}
						});
						attributeEditor.minimumWidth = item.getBounds(currentCol).width;
						attributeEditor.setEditor(combo, item, currentCol);
						break;
					}
					case "com.github.cdisk.xtrans.core.BaseComponent": {
						Combo combo = new Combo(attributeTree, SWT.NONE);
						combo.addFocusListener(focusListener);
						combo.setForeground(item.getForeground());
						for (BaseComponent component : Operation.CONFIG.components) {
							if (AttributeBoxLoader.this.component.getId().equals(component.getId())) continue;
							combo.add(component.getId());
						}
						combo.setText(item.getText(currentCol));
						combo.setFocus();
						combo.addModifyListener(new ModifyListener() {
							@Override
							public void modifyText(ModifyEvent e) {
								/* 将修改值设置回对象 */
								componentSetValue(name, Operation.CONFIG.findComponentById(combo.getText())); // 更新对象属性
								item.setText(currentCol, combo.getText()); // 更新属性面板
								context.getCanvas().redraw(); // 修改了，应该重绘
							}
						});
						attributeEditor.minimumWidth = item.getBounds(currentCol).width;
						attributeEditor.setEditor(combo, item, currentCol);
						break;
					}
					case "int":
					case "java.lang.Integer": {
						Text text = new Text(attributeTree, SWT.LEFT);
						text.addFocusListener(focusListener);
						text.setForeground(item.getForeground());
						text.setText(item.getText(currentCol));
						text.selectAll();
						text.setFocus();
						text.addVerifyListener(new VerifyListener() {
							public void verifyText(VerifyEvent e) {
								boolean b = ("0123456789".indexOf(e.text) >= 0);
								e.doit = b;
							}
						});
						text.addModifyListener(new ModifyListener() {
							@Override
							public void modifyText(ModifyEvent e) {
								/* 将修改值设置回对象 */
								Integer newValue = null;
								if (StringUtils.isNotEmpty(text.getText())) {
									newValue = Integer.parseInt(text.getText());
								}
								componentSetValue(name, newValue); // 更新对象属性值
								item.setText(currentCol, text.getText()); // 更新属性面板
								context.getCanvas().redraw(); // 修改了，应该重绘
							}
						});
						attributeEditor.minimumWidth = item.getBounds(currentCol).width;
						attributeEditor.setEditor(text, item, currentCol);
						break;
					}
					case "java.lang.String": {
						if ("sql".equals(name)) { // 如果是SQL属性，则用SQL编辑框
							SqlTextDialog dialog = new SqlTextDialog(attributeTree.getShell(), SWT.CLOSE);
							MoreButtonText moreText = new MoreButtonText(attributeTree, dialog, SWT.NONE);
							moreText.addFocusListener(focusListener);
							moreText.setData(currentId);
							moreText.setForeground(item.getForeground());
							moreText.setText(item.getText(currentCol));
							moreText.selectAll();
							moreText.setFocus();
							moreText.addModifyListener(new ModifyListener() {
								@Override
								public void modifyText(ModifyEvent e) {
									/* 将修改值设置回对象 */
									componentSetValue(name, moreText.getText()); // 更新对象属性
									item.setText(currentCol, moreText.getText()); // 更新属性面板
									context.getCanvas().redraw(); // 修改了，应该重绘
								}
							});
							attributeEditor.minimumWidth = item.getBounds(currentCol).width;
							attributeEditor.setEditor(moreText, item, currentCol);
						} else {
							TextDialog dialog = new TextDialog(attributeTree.getShell(), SWT.CLOSE);
							MoreButtonText moreText = new MoreButtonText(attributeTree, dialog, SWT.NONE);
							moreText.addFocusListener(focusListener);
							moreText.setData(currentId);
							moreText.setForeground(item.getForeground());
							moreText.setText(item.getText(currentCol));
							moreText.selectAll();
							moreText.setFocus();
							moreText.addModifyListener(new ModifyListener() {
								@Override
								public void modifyText(ModifyEvent e) {
									/* 将修改值设置回对象 */
									componentSetValue(name, moreText.getText()); // 更新对象属性
									item.setText(currentCol, moreText.getText()); // 更新属性面板
									context.getCanvas().redraw(); // 修改了，应该重绘
								}
							});
							attributeEditor.minimumWidth = item.getBounds(currentCol).width;
							attributeEditor.setEditor(moreText, item, currentCol);
						}
						break;
					}
					case "[Ljava.lang.String;": {
						TextDialog dialog = new TextDialog(attributeTree.getShell(), SWT.CLOSE);
						MoreButtonText moreText = new MoreButtonText(attributeTree, dialog, SWT.NONE);
						moreText.addFocusListener(focusListener);
						moreText.setData(currentId);
						moreText.setForeground(item.getForeground());
						moreText.setText(item.getText(currentCol));
						moreText.selectAll();
						moreText.setFocus();
						moreText.addModifyListener(new ModifyListener() {
							@Override
							public void modifyText(ModifyEvent e) {
								String[] newValue = moreText.getText().split("\r?\n");
								/* 将修改值设置回对象 */
								componentSetValue(name, newValue); // 更新对象属性
								String displayValue = "";
								for (Object o : newValue) {
									displayValue += o + "\r\n";
								}
								item.setText(currentCol, displayValue); // 更新属性面板
								context.getCanvas().redraw(); // 修改了，应该重绘
							}
						});
						attributeEditor.minimumWidth = item.getBounds(currentCol).width;
						attributeEditor.setEditor(moreText, item, currentCol);
					}
					default: {
						try {
							Class<?> clazz = Class.forName(type);
							if (clazz.isEnum()) {
								Combo combo = new Combo(attributeTree, SWT.NONE);
								combo.addFocusListener(focusListener);
								combo.setForeground(item.getForeground());
								for (Object object : clazz.getEnumConstants()) {
									combo.add(String.valueOf(object));
								}
								combo.setText(item.getText(currentCol));
								combo.setFocus();
								combo.addModifyListener(new ModifyListener() {
									@Override
									public void modifyText(ModifyEvent e) {
										/* 将修改值设置回对象 */
										Object rst = null;
										for (Object object : clazz.getEnumConstants()) {
											if (String.valueOf(object).equals(combo.getText())) {
												rst = object;
												break;
											}
										}
										componentSetValue(name, rst); // 更新对象属性
										item.setText(currentCol, combo.getText()); // 更新属性面板
										context.getCanvas().redraw(); // 修改了，应该重绘
									}
								});
								attributeEditor.minimumWidth = item.getBounds(currentCol).width;
								attributeEditor.setEditor(combo, item, currentCol);
								break;
							}
						} catch (ClassNotFoundException e1) {
							e1.printStackTrace();
						}
					}
				}
				setChildrenCheck(item);
			}
		});

	}

	private int getColId(Tree tree, TreeItem item, Point clickPoint) {
		int column = -1;
		for (int i = 0, n = tree.getColumnCount(); i < n; i++) {
			Rectangle rect = item.getBounds(i);// 得到各列的边界
			if (rect.contains(clickPoint)) {
				column = i;
				break;
			}
		}
		return column;
	}

	private TreeItem getCurrentItem(Tree tree, int clickY) {
		TreeItem item = null;
		int firstColWidth = tree.getColumn(0).getWidth();
		for (int i = 0; i < firstColWidth; i++) {
			item = tree.getItem(new Point(i, clickY));
			if (item != null)
				return item;
		}
		return item;
	}

	private void setChildrenCheck(TreeItem parent) {
		TreeItem[] children = parent.getItems();
		if (parent.getChecked()) {
			for (int i = 0; i < children.length; i++) {
				children[i].setChecked(true);
				setChildrenCheck(children[i]);
			}
		} else {
			for (int i = 0; i < children.length; i++) {
				children[i].setChecked(false);
				setChildrenCheck(children[i]);
			}
		}
	}
	
	/**
	 * 清除编辑状态
	 */
	public void clearEditor() {
		Control old = attributeEditor.getEditor();
		if (old != null) {
			old.dispose();
		}
	}

	/**
	 * 加载属性面板
	 * @param component
	 */
	public void load(BaseComponent component) {
		this.component = component;
		
		/* 清空上一次面板状态 */
		this.clearEditor();
		attributeTree.removeAll(); // 移除所有内容

		if (component == null) return; // 为空就到此为止。
		
		currentType = component.getClass().getSimpleName();
		currentId = component.getId();

		/* 获取组件的所有字段，在下一段代码中进行属性字段的筛选并处理。 */
		List<Field> fieldList = ComponentReflect.GetAttribute(component);

		{
			/* 默认给属性增加一个“类型”属性，但不可修改。（不可修改要在编辑处理过程中进行限制） */
			TreeItem treeItem = new TreeItem(attributeTree, SWT.NONE);
			treeItem.setText("基础");
			TreeItem newItem = new TreeItem(treeItem, SWT.NONE);
			newItem.setText(new String[] { "type", currentType, "" });
		}

		/* 循环字段，并筛选属性字段 */
		for (Field field : fieldList) {
			/* 筛选属性字段，不是属性字段，则跳过。 */
			Attribute attribute = field.getAnnotation(Attribute.class);

			/* 获取属性的分组，如果分组不存在，则创建分组。 */
			String group = attribute.group();
			TreeItem[] treeItems = attributeTree.getItems();
			TreeItem treeItem = null;
			for (TreeItem item : treeItems) {
				if (item.getText().equals(group)) {
					treeItem = item;
					break;
				}
			}
			if (treeItem == null) {
				treeItem = new TreeItem(attributeTree, SWT.NONE);
				treeItem.setText(group);
			}

			/* 获取属性值和属性类型 */
			String type = "java.lang.String";
			String value = "";
			try {
				Object obj = field.get(component);
				type = field.getType().getName();
				if (obj != null) {
					if (obj instanceof BaseComponent) {
						value = ((BaseComponent) obj).getId();
					} else if (obj instanceof Connect) {
						value = ((Connect) obj).getId();
					} else if (obj.getClass().isArray()) {
						for (Object o : (Object[]) obj) {
							value += String.valueOf(o) + "\r\n";
						}
					} else {
						value = String.valueOf(field.get(component));
					}
				}
			} catch (IllegalArgumentException | IllegalAccessException e) {
				e.printStackTrace();
			}

			/* 在属性面板中创建属性条目 */
			TreeItem newItem = new TreeItem(treeItem, SWT.NONE);
			newItem.setText(new String[] { field.getName(), value, attribute.value() });
			newItem.setData("type", type);

			treeItem.setExpanded(true); // 设置分组默认展开
		}
	}

	/**
	 * 给元件对象设置属性值
	 * @param fieldName
	 * @param value
	 */
	private void componentSetValue(String fieldName, Object value) {
		Field field = null;
		Class<?> clazz = component.getClass();
		for (; clazz != Object.class; clazz = clazz.getSuperclass()) {
			Field[] fields = clazz.getDeclaredFields();
			for (Field f : fields) {
				if (f.getName().equals(fieldName)) {
					field = f;
					break;
				}
			}
			if (field != null) break;
		}
		field.setAccessible(true);
		try {
			field.set(component, value);
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
	}
	
}
